home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Contributed / SpriteWorld / SpriteWorld Files / BlitPixie / Sources / BlitPixieDoubleRects.c < prev    next >
Encoding:
Text File  |  2000-10-06  |  15.9 KB  |  706 lines  |  [TEXT/CWIE]

  1. ///--------------------------------------------------------------------------------------
  2. //        BlitPixieDoubleRects
  3. //
  4. //        a blitter to merge two offscreen areas into one onscreen area
  5. //
  6. //        Written by Anders F Björklund <afb@algonet.se>, Nov. 1999
  7. //        ©1997-99 afb. All rights reserved. 
  8. ///--------------------------------------------------------------------------------------
  9.  
  10. #ifndef __BLITPIXIE__
  11. #include "BlitPixieHeader.h"
  12. #endif
  13.  
  14. #include "BlitPixieAsm.h"
  15.  
  16. #pragma mark *** PowerPC asm:
  17. #if USE_PPC_ASSEMBLY
  18.  
  19.     //    NOTE:    This implementation _always_ blits aligned doubles to the screen
  20.     //                by using a temporary buffer if needed (to avoid alignment exceptions)
  21.  
  22.     //    NOTE:    Assumes rows > 0
  23.     //            Aligning code assumes that rowBytes is multiple of 4
  24.  
  25.  
  26.     // Note: the following definitions avoids a bug in CodeWarrior Pro 5's assembler,
  27.     //   where bnl instructions are mistakenly compiled to bgel, instead of bnl or bge.
  28.     //   Geez Metrowerks, be more careful next time!
  29.  
  30. #define IF_SET        0x0C            // constant for BO field
  31. #define IF_NOT        0x04            // constant for BO field
  32.  
  33. ASM_FUNC void BlitPixieDoubleRects(
  34.     register unsigned char *src,
  35.     register unsigned char *dst,
  36.     register unsigned short bytesA,
  37.     register unsigned short bytesB,
  38.     register unsigned short rows,
  39.     register BlitPixieOffsetInfoPtr info)
  40. {
  41. #define r_temp                r31    
  42. #define r_y                    r31        // recycled
  43. #define r_alignA            r30
  44. #define r_alignB            r29
  45. #define r_leftdoubles        r30        // recycled
  46. #define r_rightdoubles        r29        // recycled
  47.  
  48. #define r_srcOffsetAtoB        r28
  49. #define r_srcOffsetBtoA        r27
  50. #define r_dstOffsetAtoB        r26
  51. #define r_dstOffsetBtoA        r25
  52.  
  53. #define r_leftblocks        r24
  54. #define r_left                r23
  55. #define r_rightblocks        r22
  56. #define r_right                r21
  57.  
  58. #define r_buffer            r20
  59. #define r_offset            r19
  60.  
  61. #define    kRegisterSaveStack    (13 * 4)        // # registers to save * sizeof(register)
  62.  
  63.     ASM_BEGIN
  64.     stmw     r19,-kRegisterSaveStack(SP)    // save registers on stack (in the "red zone")
  65.     
  66. // PARAMETERS:
  67. #define r_src        r3
  68. #define r_dst        r4
  69. #define r_bytesA    r5
  70. #define r_bytesB    r6
  71. #define r_rows        r7
  72. #define r_info        r8
  73.  
  74. //    srcOffsetAtoB = info->srcOffsetAtoB;
  75. //    srcOffsetBtoA = info->srcOffsetBtoA;
  76. //    dstOffsetAtoB = info->dstOffsetAtoB;
  77. //    dstOffsetBtoA = info->dstOffsetBtoA;
  78.     lwz     r_srcOffsetAtoB,0(info)
  79.     lwz     r_srcOffsetBtoA,4(info)
  80.     lwz     r_dstOffsetAtoB,8(info)
  81.     lwz     r_dstOffsetBtoA,12(info)
  82.  
  83.         // get a cache-block (32 byte) aligned stack storage for the (32 byte) buffer
  84.     addi        r_buffer,SP,-(kRegisterSaveStack + 32)
  85.     rlwinm        r_buffer,r_buffer,0,0,26    
  86.     dcbz        r0,r_buffer
  87.     
  88.         // alignment offset for rect A
  89.     neg        r_alignA,r4
  90.     rlwinm    r_alignA,r_alignA,0,29,31
  91.     cmplw    r_alignA,r_bytesA
  92.     ble        @alignAok
  93.     mr        r_alignA,r_bytesA
  94. @alignAok:
  95.  
  96.         // compute source alignment for A
  97.     neg        r9,r3
  98.     rlwinm    r9,r9,0,30,31
  99.  
  100.         // alignment offset for rect B
  101.     add        r0,r_bytesA,r_dstOffsetAtoB
  102.     add        r_alignB,r4,r0
  103.     neg        r_alignB,r_alignB
  104.     rlwinm    r_alignB,r_alignB,0,29,31
  105.     cmplw    r_alignB,r_bytesB
  106.     ble        @alignBok
  107.     mr        r_alignB,r_bytesB
  108. @alignBok:
  109.  
  110.         // compute source alignment for B
  111.     add        r0,r_bytesA,r_srcOffsetAtoB
  112.     add        r10,r3,r0
  113.     neg        r10,r10
  114.     rlwinm    r10,r10,0,30,31
  115.  
  116.     sub        r_bytesA,r_bytesA,r_alignA
  117.     sub        r_bytesB,r_bytesB,r_alignB
  118.  
  119. // ———————————————————————————————————————————————————————————————————————————
  120.  
  121.         //pre-calculate transfer sizes
  122.     rlwinm   r_leftblocks,r_bytesA,32-5,5,31    //    leftblocks = bytesA / 32;
  123.     rlwinm   r_left,r_bytesA,0,27,31            //    left = bytesA % 32;
  124.     rlwinm   r_rightblocks,r_bytesB,32-5,5,31    //    rightblocks = bytesB / 32;
  125.     rlwinm   r_right,r_bytesB,0,27,31            //    right = bytesB % 32;
  126.  
  127.     mfcr    r0        // save the CR in r0
  128. //    NOTE : don't use r0 from here and below (except as zero)
  129.  
  130. //     NOTE: condition register usage below: (• = unused)
  131. //                    lt            gt            eq            so    
  132. //            cr0        <-------------rows (y)--------------------->
  133. //            cr1        •            •            •            •
  134. //            cr2        A aligned ?    <-------alignA & 7------------->
  135. //            cr3        <--------------left > 32------------------->
  136. //            cr4        left > 8    <--------left & 7--------------> (or just left % 32 > 0)
  137. //            cr5        B aligned ?    <-------alignB & 7------------->
  138. //            cr6        <-------------right > 32------------------->
  139. //            cr7        right > 8    <--------right & 7-------------> (or just right % 32 > 0)
  140.     
  141.     rlwinm  r_alignA,r_alignA,5*4,9,11
  142.     rlwinm  r_alignB,r_alignB,2*4,21,23
  143.  
  144.     mtcrf    1<<(7-2),r_alignA            // cr2 = alignA & 7
  145.     mtcrf    1<<(7-5),r_alignB            // cr5 = alignB & 7
  146.  
  147.     rlwinm  r_alignA,r_alignA,32-5*4,29,31    // shift back to normal again
  148.     rlwinm  r_alignB,r_alignB,32-2*4,29,31
  149.  
  150.     lwz        r_temp,gBlitPixieProcessorType(RTOC)
  151.     lha        r_temp,0(r_temp)
  152.     cmplwi    r_temp,k601                // can we blit unaligned doubles ? (i.e. on a PPC 601)
  153.     bne        @cantBlitUnaligned
  154.  
  155. @canBlitUnaligned:
  156.     creqv    0*4+2,0*4+2,0*4+2        // crset cr0_EQ
  157.     creqv    1*4+2,1*4+2,1*4+2        // crset cr1_EQ
  158.     b        @endcantBlitUnaligned
  159.  
  160. @cantBlitUnaligned:
  161.     rlwinm    r_temp,r_alignA,0,30,31
  162.     cmplwi    cr4,r_left,0                // cr4 = left > 0 (for unaligned)
  163.     cmplw    cr0,r_temp,r9
  164.     rlwinm    r_temp,r_alignB,0,30,31
  165.     cmplwi    cr7,r_right,0                // cr7 = right > 0 (for unaligned)
  166.     cmplw    cr1,r_temp,r10
  167. @endcantBlitUnaligned:    
  168.  
  169.     cmplwi    cr3,r_leftblocks,0        // cr3 = left > 32
  170.     cmplwi    cr6,r_rightblocks,0        // cr6 = right > 32
  171.     
  172.     bne        cr0,@skipLeftAlign
  173.     rlwinm. r_leftdoubles,r_left,32-3,30,31
  174.     rlwinm  r_temp,r_left,3*4,17,19
  175.     creqv    2*4+0,2*4+0,2*4+0        // cr2_LT = is left aligned ? = true
  176.     mtcrf    1<<(7-4),r_temp            // cr4 = left & 7 (for aligned)
  177.     crnor    4*4+0,0*4+2,0*4+2        // cr4_LT = left > 8 (for aligned)
  178. @skipLeftAlign:
  179.  
  180.     bne        cr1,@skipRightAlign
  181.     rlwinm. r_rightdoubles,r_right,32-3,30,31
  182.     rlwinm  r_temp,r_right,0*4,29,31
  183.     creqv    5*4+0,5*4+0,5*4+0        // cr5_LT = is right aligned ? = true
  184.     mtcrf    1<<(7-7),r_temp            // cr7 = right & 7 (for aligned)
  185.     crnor    7*4+0,0*4+2,0*4+2        // cr7_LT = right > 8 (for aligned)
  186. @skipRightAlign:
  187.  
  188.     mr        r_y,r_rows
  189.  
  190.     li        r_offset,32
  191.     subi    r3,r3,32
  192.     subi    r4,r4,32
  193.     
  194. //  NOTE: from here on, regs r5-r12 are scratch!
  195. @rowloop:
  196. // ——————————————————————————————————————————————————————————————————————————— RECT A (left)
  197.  
  198.             // align destination to 8-byte boundary
  199.         bc        IF_NOT,2*4+3, @skipalignAByte
  200.         lbz        r5,32(r3)
  201.         addi    r3,r3,1
  202.         stb        r5,32(r4)
  203.         addi    r4,r4,1
  204.     @skipalignAByte:
  205.         bc        IF_NOT,2*4+2, @skipalignAWord
  206.         lhz        r5,32(r3)
  207.         addi    r3,r3,2
  208.         sth        r5,32(r4)
  209.         addi    r4,r4,2
  210.     @skipalignAWord:
  211.         bc        IF_NOT,2*4+1, @skipalignALong
  212.         lwz        r5,32(r3)
  213.         addi    r3,r3,4
  214.         stw        r5,32(r4)
  215.         addi    r4,r4,4
  216.     @skipalignALong:
  217.     
  218.         bc        IF_SET,2*4+0, @leftAligned
  219.         
  220.     // --------------------------------- NOT ALIGNED
  221.     @leftNotAligned:
  222.     
  223.         mtctr     r_leftblocks
  224.         mtxer     r_left
  225.         
  226.             // copy 32 byte blocks (w/ buffer)
  227.         beq         cr3,@skipleft
  228.     @leftloop:    
  229.         lwzu     r5,32(r3)
  230.         lwz      r6,4(r3)
  231.         lwz      r7,8(r3)
  232.         lwz      r8,12(r3)
  233.         lwz      r9,16(r3)
  234.         lwz      r10,20(r3)
  235.         lwz      r11,24(r3)
  236.         lwz      r12,28(r3)
  237.         stw      r5,0(r_buffer)
  238.         stw      r6,4(r_buffer)
  239.         stw      r7,8(r_buffer)
  240.         stw      r8,12(r_buffer)
  241.         stw      r9,16(r_buffer)
  242.         stw      r10,20(r_buffer)
  243.         stw      r11,24(r_buffer)
  244.         stw      r12,28(r_buffer)
  245.         lfd      fp1,0(r_buffer)
  246.         lfd      fp2,8(r_buffer)
  247.         lfd      fp3,16(r_buffer)
  248.         lfd      fp4,24(r_buffer)
  249.         stfdu    fp1,32(r4)
  250.         stfd     fp2,8(r4)
  251.         stfd     fp3,16(r4)
  252.         stfd     fp4,24(r4)
  253.         bdnz     @leftloop
  254.     @skipleft:
  255.     
  256.             // copy left-over bytes (<32)
  257.         beq        cr4,@endleft
  258.         lswx    r5,r_offset,r3
  259.         add        r3,r3,r_left
  260.         stswx    r5,r_offset,r4
  261.         add        r4,r4,r_left
  262.         b        @endleft
  263.  
  264.     // --------------------------------- ALIGNED
  265.  
  266.     @leftAligned:    // copy 32 byte blocks (wo/ buffer)
  267.  
  268.         beq         cr3,@skipleftAligned
  269.         mtctr     r_leftblocks
  270.     @leftloopAligned:
  271.         lfdu     fp1,32(r3)
  272.         lfd      fp2,8(r3)
  273.         lfd      fp3,16(r3)
  274.         lfd      fp4,24(r3)
  275.         stfdu    fp1,32(r4)
  276.         stfd     fp2,8(r4)
  277.         stfd     fp3,16(r4)
  278.         stfd     fp4,24(r4)
  279.         bdnz     @leftloopAligned
  280.     @skipleftAligned:
  281.  
  282.             // copy left-over bytes (<32)
  283.         bc         IF_NOT,4*4+0, @skipADoubles
  284.         mtctr     r_leftdoubles
  285.     @leftloopDouble:
  286.         lfd      fp0,32(r3)
  287.         addi     r3,r3,8
  288.         stfd     fp0,32(r4)
  289.         addi     r4,r4,8
  290.         bdnz     @leftloopDouble
  291.     @skipADoubles:
  292.         bc         IF_NOT,4*4+1, @skipALong
  293.         lwz         r5,32(r3)
  294.         addi     r3,r3,4
  295.         stw         r5,32(r4)
  296.         addi     r4,r4,4
  297.     @skipALong:
  298.         bc         IF_NOT,4*4+2, @skipAWord
  299.         lhz         r5,32(r3)
  300.         addi     r3,r3,2
  301.         sth         r5,32(r4)
  302.         addi     r4,r4,2
  303.     @skipAWord:
  304.         bc         IF_NOT,4*4+3, @skipAByte
  305.         lbz         r5,32(r3)
  306.         addi     r3,r3,1
  307.         stb       r5,32(r4)
  308.         addi     r4,r4,1
  309.     @skipAByte:
  310.     
  311.     @endleft:
  312.         add     r3,r3,r_srcOffsetAtoB
  313.         add     r4,r4,r_dstOffsetAtoB
  314.  
  315. // ——————————————————————————————————————————————————————————————————————————— RECT B (right)
  316.     
  317.             // align destination to 8-byte boundary
  318.         bc        IF_NOT,5*4+3, @skipalignBByte
  319.         lbz        r5,32(r3)
  320.         addi    r3,r3,1
  321.         stb        r5,32(r4)
  322.         addi    r4,r4,1
  323.     @skipalignBByte:
  324.         bc        IF_NOT,5*4+2, @skipalignBWord
  325.         lhz        r5,32(r3)
  326.         addi    r3,r3,2
  327.         sth        r5,32(r4)
  328.         addi    r4,r4,2
  329.     @skipalignBWord:
  330.         bc        IF_NOT,5*4+1, @skipalignBLong
  331.         lwz        r5,32(r3)
  332.         addi    r3,r3,4
  333.         stw        r5,32(r4)
  334.         addi    r4,r4,4
  335.     @skipalignBLong:
  336.     
  337.         bc        IF_SET,5*4+0, @rightAligned
  338.         
  339.     // --------------------------------- UNALIGNED
  340.     @rightNotAligned:
  341.     
  342.         mtctr     r_rightblocks
  343.         mtxer     r_right
  344.  
  345.             // copy 32 byte blocks (w/ buffer)
  346.         beq         cr6,@skipright
  347.     @rightloop:    
  348.         lwzu     r5,32(r3)
  349.         lwz      r6,4(r3)
  350.         lwz      r7,8(r3)
  351.         lwz      r8,12(r3)
  352.         lwz      r9,16(r3)
  353.         lwz      r10,20(r3)
  354.         lwz      r11,24(r3)
  355.         lwz      r12,28(r3)
  356.         stw      r5,0(r_buffer)
  357.         stw      r6,4(r_buffer)
  358.         stw      r7,8(r_buffer)
  359.         stw      r8,12(r_buffer)
  360.         stw      r9,16(r_buffer)
  361.         stw      r10,20(r_buffer)
  362.         stw      r11,24(r_buffer)
  363.         stw      r12,28(r_buffer)
  364.         lfd      fp1,0(r_buffer)
  365.         lfd      fp2,8(r_buffer)
  366.         lfd      fp3,16(r_buffer)
  367.         lfd      fp4,24(r_buffer)
  368.         stfdu    fp1,32(r4)
  369.         stfd     fp2,8(r4)
  370.         stfd     fp3,16(r4)
  371.         stfd     fp4,24(r4)
  372.         bdnz     @rightloop
  373.     @skipright:
  374.     
  375.             // copy left-over bytes (<32)
  376.         beq        cr7,@endright
  377.         lswx    r5,r_offset,r3
  378.         add        r3,r3,r_right
  379.         stswx    r5,r_offset,r4
  380.         add        r4,r4,r_right
  381.         b        @endright
  382.  
  383.     // --------------------------------- ALIGNED
  384.     
  385.             // copy 32 byte blocks (wo/ buffer)
  386.     @rightAligned: 
  387.         
  388.         beq         cr6,@skiprightAligned
  389.         mtctr     r_rightblocks
  390.     @rightloopAligned:
  391.         lfdu     fp1,32(r3)
  392.         lfd      fp2,8(r3)
  393.         lfd      fp3,16(r3)
  394.         lfd      fp4,24(r3)
  395.         stfdu    fp1,32(r4)
  396.         stfd     fp2,8(r4)
  397.         stfd     fp3,16(r4)
  398.         stfd     fp4,24(r4)
  399.         bdnz     @rightloopAligned
  400.     @skiprightAligned:
  401.  
  402.             // copy left-over bytes (<32)
  403.         bc         IF_NOT,7*4+0, @skipBDoubles
  404.         mtctr     r_rightdoubles
  405.     @rightloopDouble:
  406.         lfd      fp0,32(r3)
  407.         addi     r3,r3,8
  408.         stfd     fp0,32(r4)
  409.         addi     r4,r4,8
  410.         bdnz     @rightloopDouble
  411.     @skipBDoubles:
  412.         bc         IF_NOT,7*4+1, @skipBLong
  413.         lwz         r5,32(r3)
  414.         addi     r3,r3,4
  415.         stw         r5,32(r4)
  416.         addi     r4,r4,4
  417.     @skipBLong:
  418.         bc         IF_NOT,7*4+2, @skipBWord
  419.         lhz         r5,32(r3)
  420.         addi     r3,r3,2
  421.         sth         r5,32(r4)
  422.         addi     r4,r4,2
  423.     @skipBWord:
  424.         bc         IF_NOT,7*4+3, @skipBByte
  425.         lbz         r5,32(r3)
  426.         addi     r3,r3,1
  427.         stb       r5,32(r4)
  428.         addi     r4,r4,1
  429.     @skipBByte:
  430.     
  431.     @endright:
  432.     
  433. // ———————————————————————————————————————————————————————————————————————————
  434.  
  435.         subic.   r_y,r_y,1
  436.  
  437.         add      r3,r3,r_srcOffsetBtoA
  438.         add      r4,r4,r_dstOffsetBtoA
  439.         
  440.     bne @rowloop
  441.  
  442. @end:
  443.     mtcrf    0xFF,r0            // restore the CR    (mtcr r0)
  444. @gohome:
  445.     lmw     r19,-kRegisterSaveStack(SP)        // restore registers from stack
  446.  
  447.     ASM_END
  448. }
  449.  
  450. #pragma mark *** 680X0 asm:
  451. #elif USE_68K_ASSEMBLY
  452.  
  453. //        NOTE:    Assumes rows > 0
  454.  
  455. //        NOTE:    Aligning code assumes that rowBytes is multiple of 4
  456.  
  457. ASM_FUNC void BlitPixieDoubleRects(
  458.     unsigned char *src,
  459.     unsigned char *dst,
  460.     unsigned short bytesA,
  461.     unsigned short bytesB,
  462.     unsigned short rows,
  463.     BlitPixieOffsetInfoPtr info)
  464. {
  465. //    VARIABLE(S)        REGISTER
  466. //    *temp*            D0
  467. //    *temp*,y        D1
  468. //    bytesA,left        D2
  469. //    leftblocks        D3
  470. //    bytesB,right    D4
  471. //    dst                D5
  472. //    alignA            D6
  473. //    alignB            D7
  474. //    src                A0
  475. //    dst                A1
  476. //    startA            A2
  477. //    startB            A3
  478. //    offsetinfoptr    A4
  479.  
  480.     ASM_BEGIN
  481.  
  482.     MOVEM.L      D3-D7/A2-A4,-(SP)
  483.  
  484.     MOVEA.L      src,A0   
  485.      MOVEA.L      dst,A1
  486.     CLR.L      D2
  487.     MOVE.W    bytesA,D2
  488.      CLR.L      D4
  489.     MOVE.W    bytesB,D4
  490.     MOVEA.L      info,A4
  491.  
  492.     // srcOffsetAtoB = info->srcOffsetAtoB;
  493.     // srcOffsetBtoA = info->srcOffsetBtoA;
  494.     // dstOffsetAtoB = info->dstOffsetAtoB;
  495.     // dstOffsetBtoA = info->dstOffsetBtoA;
  496. #define D_srcOffsetAtoB        (A4)
  497. #define D_srcOffsetBtoA        4(A4)
  498. #define D_dstOffsetAtoB        8(A4)
  499. #define D_dstOffsetBtoA        12(A4)
  500.       
  501.         // alignment offset for rect A
  502.     MOVE.L    A1,D6
  503.     MOVEQ     #3,D1
  504.     NEG.L     D6
  505.     AND.W     D1,D6
  506.      CMP.W     D2,D6
  507.     BLE.S      @alignAok
  508.     MOVE.W    D2,D6
  509.  @alignAok:
  510.     SUB.W     D6,D2
  511.  
  512.         // alignment offset for rect B
  513.     MOVE.L    A1,D7
  514.     ADD.L     D2,D7
  515.     ADD.L     D_dstOffsetAtoB,D7
  516.     NEG.L     D7
  517.     AND.W     D1,D7
  518.      CMP.W     D4,D7
  519.     BLE.S      @alignBok
  520.     MOVE.W    D4,D7
  521.  @alignBok:
  522.     SUB.W     D7,D4
  523.       
  524.      MOVEQ     #15,D0
  525.    
  526.            //pre-calculate transfer sizes for rect A
  527.     MOVE.W    D2,D3
  528.     LSR.W     #6,D3
  529.     MOVE.W    D2,D1
  530.     ANDI.W    #3,D2
  531.     LSR.W     #2,D1        // / sizeof(long)
  532.     AND.W     D0,D1
  533.      ADD.W      D1,D1        // * sizeof(MOVE.L (A0)+,(A1)+)
  534.     LEA          @leftloopend,A2
  535.     SUBA.L      D1,A2    
  536.  
  537.            //pre-calculate transfer sizes for rect B
  538.     MOVE.W    D4,D5
  539.     LSR.W     #6,D5
  540.     MOVE.W    D4,D1
  541.     ANDI.W    #3,D4
  542.     LSR.W     #2,D1        // / sizeof(long)
  543.     AND.W      D0,D1
  544.     ADD.W      D1,D1        // * sizeof(MOVE.L (A0)+,(A1)+)
  545.     LEA          @rightloopend,A3
  546.     SUBA.L      D1,A3    
  547.  
  548.     MOVE.W    rows,D1
  549.  
  550. @rowloop:    
  551.  
  552. // ——————————————————————————————————————————————————————————————————————————— RECT A (left)
  553.  
  554.             // align destination to 4-byte boundary
  555.           MOVE.W    D6,D0
  556.           ANDI.W    #1,D0
  557.           BEQ.S    @skipalignAbyte
  558.           MOVE.B    (A0)+,(A1)+
  559.       @skipalignAbyte:
  560.           MOVE.W    D6,D0
  561.           ANDI.W    #2,D0
  562.           BEQ.S    @skipalignAword
  563.           MOVE.W    (A0)+,(A1)+
  564.       @skipalignAword:
  565.  
  566.             // copy 64 byte blocks (w/ Duff's Device)
  567.            MOVE.W    D3,D0
  568.            JMP        (A2)
  569.    @leftloop:
  570.         MOVE.L    (A0)+,(A1)+
  571.         MOVE.L     (A0)+,(A1)+
  572.         MOVE.L    (A0)+,(A1)+
  573.         MOVE.L    (A0)+,(A1)+
  574.         
  575.         MOVE.L    (A0)+,(A1)+
  576.         MOVE.L    (A0)+,(A1)+
  577.         MOVE.L     (A0)+,(A1)+
  578.         MOVE.L    (A0)+,(A1)+
  579.         
  580.         MOVE.L    (A0)+,(A1)+
  581.         MOVE.L     (A0)+,(A1)+
  582.         MOVE.L    (A0)+,(A1)+
  583.         MOVE.L    (A0)+,(A1)+
  584.         
  585.         MOVE.L    (A0)+,(A1)+
  586.         MOVE.L    (A0)+,(A1)+
  587.         MOVE.L     (A0)+,(A1)+
  588.         MOVE.L    (A0)+,(A1)+
  589.     @leftloopend:
  590.            DBRA    D0,@leftloop
  591.    
  592.               // copy left-over bytes
  593.           MOVE.W    D2,D0
  594.           BEQ.S    @skipleftbyte
  595.           SUBQ.W    #2,D0
  596.           BMI.S    @leftbyte
  597.           MOVE.W    (A0)+,(A1)+
  598.           TST      D0
  599.           BEQ.S    @skipleftbyte
  600.       @leftbyte:
  601.          MOVE.B    (A0)+,(A1)+
  602.       @skipleftbyte:
  603.      
  604.     ADDA.L    D_srcOffsetAtoB,A0
  605.     ADDA.L    D_dstOffsetAtoB,A1
  606.  
  607. // ——————————————————————————————————————————————————————————————————————————— RECT B (right)
  608.  
  609.             // align destination to 4-byte boundary
  610.           MOVE.W    D7,D0
  611.           ANDI.W    #1,D0
  612.           BEQ.S    @skipalignBbyte
  613.           MOVE.B    (A0)+,(A1)+
  614.       @skipalignBbyte:
  615.           MOVE.W    D7,D0
  616.           ANDI.W    #2,D0
  617.           BEQ.S    @skipalignBword
  618.           MOVE.W    (A0)+,(A1)+
  619.       @skipalignBword:
  620.          
  621.             // copy 64 byte blocks (w/ Duff's Device)
  622.         MOVE.W    D5,D0
  623.            JMP        (A3)
  624.    @rightloop:
  625.         MOVE.L    (A0)+,(A1)+
  626.         MOVE.L     (A0)+,(A1)+
  627.         MOVE.L    (A0)+,(A1)+
  628.         MOVE.L     (A0)+,(A1)+
  629.         
  630.         MOVE.L    (A0)+,(A1)+
  631.         MOVE.L    (A0)+,(A1)+
  632.         MOVE.L    (A0)+,(A1)+
  633.         MOVE.L     (A0)+,(A1)+
  634.         
  635.         MOVE.L    (A0)+,(A1)+
  636.         MOVE.L    (A0)+,(A1)+
  637.         MOVE.L     (A0)+,(A1)+
  638.         MOVE.L    (A0)+,(A1)+
  639.         
  640.         MOVE.L    (A0)+,(A1)+
  641.         MOVE.L    (A0)+,(A1)+
  642.         MOVE.L     (A0)+,(A1)+
  643.         MOVE.L    (A0)+,(A1)+
  644.     @rightloopend:
  645.            DBRA    D0,@rightloop
  646.     
  647.              // copy left-over bytes
  648.          MOVE.W    D4,D0
  649.           BEQ.S    @skiprightbyte
  650.           SUBQ.W    #2,D0
  651.           BMI.S    @rightbyte
  652.           MOVE.W    (A0)+,(A1)+
  653.           TST      D0
  654.           BEQ.S    @skiprightbyte
  655.       @rightbyte:
  656.          MOVE.B    (A0)+,(A1)+
  657.       @skiprightbyte:
  658.  
  659.     ADDA.L    D_srcOffsetBtoA,A0
  660.     ADDA.L    D_dstOffsetBtoA,A1
  661.  
  662. // ———————————————————————————————————————————————————————————————————————————
  663.  
  664.     SUBQ.W    #1,D1
  665.     BNE       @rowloop
  666.  
  667.  @end:
  668.     MOVEM.L      (SP)+,D3-D7/A2-A4
  669.  
  670.     ASM_END
  671. }
  672.  
  673. #pragma mark *** Generic C:
  674. #elif USE_GENERIC_C
  675.  
  676. void BlitPixieDoubleRects(
  677.     unsigned char *src,
  678.     unsigned char *dst,
  679.     unsigned short bytesA,
  680.     unsigned short bytesB,
  681.     unsigned short rows,
  682.     BlitPixieOffsetInfoPtr info)
  683. {
  684.     BLITPIXIE_ASSERT( rows > 0 );
  685.     BLITPIXIE_ASSERT( bytesA > 0 );
  686.     BLITPIXIE_ASSERT( bytesB > 0 );
  687.  
  688.     while ( rows-- )
  689.     {
  690.         BlitPixieMemCopy( dst, src, bytesA );
  691.         src += bytesA;
  692.         dst += bytesA;
  693.         
  694.         src += info->srcOffsetAtoB;
  695.         dst += info->dstOffsetAtoB;
  696.  
  697.         BlitPixieMemCopy( dst, src, bytesB );
  698.         src += bytesB;
  699.         dst += bytesB;
  700.         
  701.         src += info->srcOffsetBtoA;
  702.         dst += info->dstOffsetBtoA;
  703.     }
  704. }
  705.  
  706. #endif